package controller;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;

/**
 * Classe padrão para conversão de objetos/entidades. Geralmente é utilizada por
 * componentes faces que necessitam desta conversão, como por exemplo o
 * selectOneMenu.
 *
 * @author Rodolpho.
 */
@SessionScoped
@FacesConverter(value = "genericConverter")
public class GenericConverter implements Converter {

    /**
     * Obtém o objeto.
     *
     * @param ctx
     * @param component
     * @param value
     * @return Object
     */
    @Override
    public Object getAsObject(FacesContext ctx, UIComponent component, String value) {
        if (value != null) {
            return component.getAttributes().get(value);
        }
        return null;
    }

    /**
     * Obtém o objeto convertido em String.
     *
     * @param ctx
     * @param component
     * @param value
     * @return String
     */
    @Override
    public String getAsString(FacesContext ctx, UIComponent component, Object obj) {
        if (obj != null && !"".equals(obj)) {
            String id = null;
            Class clazz = component.getValueExpression("value").getType(ctx.getELContext());

            try {
                Field idField = null;
                for (Method method : clazz.getDeclaredMethods()) {
                    if ((method.getAnnotation(Id.class) != null) || (method.getAnnotation(EmbeddedId.class) != null)) {
                        String att = method.getName();
                        if (method.getName().substring(0, 3).contains("get")) {
                            att = method.getName().substring(3);
                        } else if (method.getName().substring(0, 2).contains("is")) {
                            att = method.getName().substring(2);
                        }
                        String prefix = att.substring(0, 1).toLowerCase();
                        String sufix = att.substring(1);
                        String finalString = prefix + sufix;
                        Field privateField = clazz.getDeclaredField(finalString);
                        privateField.setAccessible(true);
                        idField = privateField;
                    }
                }

                if (idField != null) {
                    if (idField.get(clazz.cast(obj)) != null) {
                        Object objClazz = clazz.cast(obj);
                        Object objcast = idField.get(objClazz);
                        id = objcast.toString();
                    }

                    if (id == null) {
                        id = "";
                    }

                    id = id.trim();
                    component.getAttributes().put(id, component.getValueExpression("value").getType(ctx.getELContext()).cast(obj));
                    return id;
                }
            } catch (Exception e) {
            }
        }
        return null;
    }
}
